package com.ruoyi.oss.template;

import com.ruoyi.common.exception.ServiceException;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class MinioTemplate implements OssTemplate {

    private final MinioClient client;

    public MinioTemplate(MinioClient client) {
        this.client = client;
    }

    public boolean objectExists(String destBucketName, String fileName) {
        try {
            client.statObject(destBucketName, fileName);
            return true ;
        } catch (Exception e) {
            return false ;
        }
    }

    @Override
    public void makeBucket(String bucketName) {
        try {
            client.makeBucket(bucketName);
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public void removeBucket(String bucketName) {
        try {
            client.removeBucket(bucketName);
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public boolean bucketExists(String bucketName) {
        try {
            return client.bucketExists(bucketName);
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public void copyFile(String srcBucketName, String fileName, String destBucketName) {
        if(!objectExists(srcBucketName, fileName)) {
            throw new ServiceException("桶(" + srcBucketName + ")中的" + fileName + "源文件不存在") ;
        }
        if(objectExists(destBucketName, fileName)) {
            throw new ServiceException("桶(" + destBucketName + ")中的" + fileName + "文件已经存在") ;
        }
        try {
            client.copyObject(destBucketName, fileName, null, null,
                    srcBucketName, fileName, null, null);
        }  catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public void copyFile(String srcBucketName, String fileName, String destBucketName, String destFileName) {
        if(!objectExists(srcBucketName, fileName)) {
            throw new ServiceException("桶(" + srcBucketName + ")中的" + fileName + "源文件不存在") ;
        }
        if(objectExists(destBucketName, destFileName)) {
            throw new ServiceException("桶(" + destBucketName + ")中的" + fileName + "文件已经存在") ;
        }
        try {
            client.copyObject(destBucketName, destFileName, null, null,
                    srcBucketName, fileName, null, null);
        }  catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public InputStream getInputStream(String bucketName, String fileName) {
        try {
            return client.getObject(bucketName, fileName, 60 * 60) ;
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public String generalUploadPath(String bucketName, String fileName)  {
        try {
            return client.getPresignedObjectUrl(Method.PUT, bucketName, fileName, 60 * 60, null) ;
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public String getDownloadPath(String bucketName, String fileName) {
        try {
           return client.presignedGetObject(bucketName, fileName, 60 * 60) ;
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public String getPlayPath(String bucketName, String fileName) {
        try {
            return client.presignedGetObject(bucketName, fileName, 60 * 60 * 8) ;
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public void putFile(String bucketName, String fileName, MultipartFile file) {
        if(objectExists(bucketName, fileName)) {
            throw new ServiceException("桶(" + bucketName + ")中的" + fileName + "文件已经存在") ;
        }

        try {
            PutObjectOptions putObjectOptions = new PutObjectOptions(file.getSize(), -1);
            InputStream stream = file.getInputStream();
            this.client.putObject(bucketName, fileName, stream, putObjectOptions);
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public void putFile(String bucketName, String fileName, InputStream stream) {
        if(objectExists(bucketName, fileName)) {
            throw new ServiceException("桶(" + bucketName + ")中的" + fileName + "文件已经存在") ;
        }
        try {
            PutObjectOptions putObjectOptions = new PutObjectOptions(stream.available(), -1);
            this.client.putObject(bucketName, fileName, stream, putObjectOptions);
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public void removeFile(String bucketName, String fileName) {
        try {
            this.client.removeObject(bucketName, fileName);
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }

    @Override
    public void removeFiles(String bucketName, List<String> fileNames) {
        this.client.removeObjects(bucketName, fileNames);
    }

    @Override
    public List<String> listObjects(String bucketName, String prefix) {
        ArrayList<String> list = new ArrayList<String>();
        try {
            Iterator<Result<Item>> iterator = this.client.listObjects(bucketName, prefix, true).iterator();
            while (iterator.hasNext()) {
                Item item = iterator.next().get();
                list.add(item.objectName());
            }
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
        return list ;
    }
    @Override
    public void merge(String bucketName, String objectName, List<String> files) {
        ArrayList<ComposeSource> composeSources = new ArrayList<>();
        for (String file : files) {
            composeSources.add(new ComposeSource("test", file));
        }


        try {
            this.client.composeObject(bucketName, objectName, composeSources, null, null);
        } catch (InternalException e) {
            throw new ServiceException("OSS网络错误") ;
        } catch (InvalidBucketNameException e) {
            throw new ServiceException("非法的桶名") ;
        } catch (InvalidKeyException e) {
            throw new ServiceException("OSS用户认证失败") ;
        }  catch (IOException e) {
            throw new ServiceException("OSS IO错误") ;
        } catch (Exception e) {
            throw new ServiceException("未知错误") ;
        }
    }
}
